
package com.av.torrent.jobs;

import com.av.torrent.Application;
import com.av.torrent.helpers.PreferencesHelper;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * @author Uladzimir_Kerus
 */
public abstract class AbstractSubscribableHttpPostJob extends AbstractSubscribableJob<JSONObject> {

  private final DefaultHttpClient mHttpClient;

  /**
   * 
   */
  public AbstractSubscribableHttpPostJob() {
    final HttpParams httpParams = createHttpParams();
    mHttpClient = new DefaultHttpClient(httpParams);
  }

  private HttpParams createHttpParams() {
    final HttpParams httpParams = new BasicHttpParams();
    HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
    return httpParams;
  }

  @Override
  public JSONObject process() {

    final PreferencesHelper preferencesHelper = Application.getInstance().getPreferencesHelper();
    final String hostname = preferencesHelper.getHost();
    final String port = String.valueOf(preferencesHelper.getPort());
    final String rpcEndpoint = "/transmission/rpc";

    final String targetUrl = "http://" + hostname + ":" + port + rpcEndpoint;

    final HttpPost httpPost = new HttpPost(targetUrl);

    final JSONObject requstBodyAsJSON = buildRequestBody();
    final String requestBodyAsString = requstBodyAsJSON.toString();
    StringEntity requstEntity = null;

    try {
      requstEntity = new StringEntity(requestBodyAsString, HTTP.UTF_8);
    } catch (final UnsupportedEncodingException ueEx) {
      throw new IllegalStateException("Unable to build request body", ueEx);
    }

    httpPost.setEntity(requstEntity);

    HttpResponse response = null;

    try {
      response = mHttpClient.execute(httpPost);
    } catch (ClientProtocolException e) {
      throw new IllegalStateException("Unable to perform request", e);
    } catch (IOException e) {
      throw new IllegalStateException("Unable to perform request", e);
    }

    int responseStatusCode = response.getStatusLine().getStatusCode();

    if (responseStatusCode != 200) {

      if (responseStatusCode == 409) {
        // we need to retry with correct "X-Transmission-Session-Id"
        httpPost.addHeader(response.getLastHeader("X-Transmission-Session-Id"));

        try {
          response = mHttpClient.execute(httpPost);
        } catch (ClientProtocolException e) {
          throw new IllegalStateException("Unable to perform request", e);
        } catch (IOException e) {
          throw new IllegalStateException("Unable to perform request", e);
        }

        responseStatusCode = response.getStatusLine().getStatusCode();

        if (responseStatusCode != 200) {
          throw new IllegalStateException(String.format("Bad response code returned from server [responseCode = %s]",
              response.getStatusLine().getStatusCode()));
        }

      } else {
        // TODO: think about re-requesting in case of abscense of
        // Transmission-Session-Id
        throw new IllegalStateException(String.format("Bad response code returned from server [responseCode = %s]",
            response.getStatusLine().getStatusCode()));
      }
    }

    String responseBodyAsString = null;

    try {
      responseBodyAsString = EntityUtils.toString(response.getEntity(), HTTP.UTF_8);
    } catch (ParseException e) {
      throw new IllegalStateException("Unable to get response content", e);
    } catch (IOException e) {
      throw new IllegalStateException("Unable to get response content", e);
    }

    JSONObject responseJsonObject = null;

    try {
      responseJsonObject = new JSONObject(responseBodyAsString);
    } catch (JSONException e) {
      throw new IllegalStateException("Response body is not a valid JSON object", e);
    }

    return responseJsonObject;
  }

  protected abstract JSONObject buildRequestBody();

}
